﻿//-----------------------------------------------------------------------
// <copyright file="Helper.cs" company="Craig Longford">
//     Copyright (c) Craig Longford. All rights reserved.
//     Email: deltawolf7@gmail.com
//     WWW: http://www.deltasblog.co.uk
// </copyright>
//-----------------------------------------------------------------------

namespace Delta.Data.DataExpress
{
    using System;
    using System.Configuration;
    using System.Configuration.Provider;
    using System.Data;
    using System.Data.Odbc;
    using System.Data.OleDb;
    using System.Data.SqlClient;
    using System.Reflection;

    /// <summary>
    /// Data access helper
    /// Handles conversion of data, connections and commands
    /// </summary>
    public static class Helper
    {
        #region Conversions
        /// <summary>
        /// Convert object to String
        /// </summary>
        /// <param name="data">Data object returned from database</param>
        /// <returns>Value as String</returns>
        public static string ToString(object data)
        {
            if (data == DBNull.Value)
            {
                return string.Empty;
            }

            return data.ToString();
        }

        /// <summary>
        /// Convert object to Boolean
        /// </summary>
        /// <param name="data">Data object returned from database</param>
        /// <returns>Value as true or false</returns>
        public static bool ToBool(object data)
        {
            if (data == DBNull.Value)
            {
                return false;
            }

            if ((ToString(data) == "1") || (ToString(data).ToUpper() == "TRUE"))
            {
                return true;
            }

            return false;
        }

        /// <summary>
        /// Convert object to INT
        /// </summary>
        /// <param name="data">Data object returned from database</param>
        /// <returns>Value as INT</returns>
        public static int ToInt(object data)
        {
            if (data == DBNull.Value)
            {
                return 0;
            }

            return int.Parse(ToString(data));
        }

        /// <summary>
        /// Convert object to UINT
        /// </summary>
        /// <param name="data">Data object returned from database</param>
        /// <returns>Value as UINT</returns>
        public static uint ToUInt(object data)
        {
            if (data == DBNull.Value)
            {
                return 0;
            }

            return uint.Parse(ToString(data));
        }

        /// <summary>
        /// Convert object to Long
        /// </summary>
        /// <param name="data">Data object returned from database</param>
        /// <returns>Value as Long</returns>
        public static long ToLong(object data)
        {
            if (data == DBNull.Value)
            {
                return 0;
            }

            return long.Parse(ToString(data));
        }

        /// <summary>
        /// Convert object to ULong
        /// </summary>
        /// <param name="data">Data object returned from database</param>
        /// <returns>Value as ULong</returns>
        public static ulong ToULong(object data)
        {
            if (data == DBNull.Value)
            {
                return 0;
            }

            return ulong.Parse(ToString(data));
        }

        /// <summary>
        /// Convert object to Short
        /// </summary>
        /// <param name="data">Data object returned from database</param>
        /// <returns>Value as Short</returns>
        public static short ToShort(object data)
        {
            if (data == DBNull.Value)
            {
                return 0;
            }

            return short.Parse(ToString(data));
        }

        /// <summary>
        /// Convert object to UShort
        /// </summary>
        /// <param name="data">Data object returned from database</param>
        /// <returns>Value as UShort</returns>
        public static ushort ToUShort(object data)
        {
            if (data == DBNull.Value)
            {
                return 0;
            }

            return ushort.Parse(ToString(data));
        }

        /// <summary>
        /// Convert object to Decimal
        /// </summary>
        /// <param name="data">Data object returned from database</param>
        /// <returns>Value as Decimal</returns>
        public static decimal ToDecimal(object data)
        {
            if (data == DBNull.Value)
            {
                return 0.0M;
            }

            return decimal.Parse(ToString(data));
        }

        /// <summary>
        /// Convert object to ENUM
        /// </summary>
        /// <typeparam name="T">Type of ENUM</typeparam>
        /// <param name="data">Data object returned from database</param>
        /// <returns>Value as ENUM</returns>
        public static T ToEnum<T>(object data)
        {
            if (data == DBNull.Value)
            {
                return (T)Enum.Parse(typeof(T), "0");
            }

            return (T)Enum.Parse(typeof(T), ToString(data));
        }

        /// <summary>
        /// Convert object to Float
        /// </summary>
        /// <param name="data">Data object returned from database</param>
        /// <returns>Value as Float</returns>
        public static float ToFloat(object data)
        {
            if (data == DBNull.Value)
            {
                return 0.0F;
            }

            return float.Parse(ToString(data));
        }

        /// <summary>
        /// Convert object to Double
        /// </summary>
        /// <param name="data">Data object returned from database</param>
        /// <returns>Value as Double</returns>
        public static double ToDouble(object data)
        {
            if (data == DBNull.Value)
            {
                return 0.0;
            }

            return double.Parse(ToString(data));
        }

        /// <summary>
        /// Convert object to Byte
        /// </summary>
        /// <param name="data">Data object returned from database</param>
        /// <returns>Value as Byte</returns>
        public static byte ToByte(object data)
        {
            if (data == DBNull.Value)
            {
                return 0;
            }

            return byte.Parse(ToString(data));
        }

        /// <summary>
        /// Convert object to SByte
        /// </summary>
        /// <param name="data">Data object returned from database</param>
        /// <returns>Value as SByte</returns>
        public static sbyte ToSByte(object data)
        {
            if (data == DBNull.Value)
            {
                return 0;
            }

            return sbyte.Parse(ToString(data));
        }

        /// <summary>
        /// Convert object to Char
        /// </summary>
        /// <param name="data">Data object returned from database</param>
        /// <returns>Value as Char</returns>
        public static char ToChar(object data)
        {
            if (data == DBNull.Value)
            {
                return ' ';
            }

            return char.Parse(ToString(data));
        }

        /// <summary>
        /// Convert object to DataTime
        /// </summary>
        /// <param name="data">Data object returned from database</param>
        /// <returns>value as DateTime</returns>
        public static DateTime ToDateTime(object data)
        {
            if (data == DBNull.Value)
            {
                return new DateTime();
            }

            return DateTime.Parse(ToString(data));
        }

        /// <summary>
        /// Convert object to GUID
        /// </summary>
        /// <param name="data">Data object returned from database</param>
        /// <returns>Value as GUID</returns>
        public static Guid ToGuid(object data)
        {
            if (data == DBNull.Value)
            {
                return Guid.Empty;
            }

            return new Guid(ToString(data));
        }
        #endregion

        #region Get Connection
        /// <summary>
        /// Get database connection
        /// </summary>
        /// <param name="connectionName">Connection string name</param>
        /// <returns>Database connection</returns>
        internal static IDbConnection GetConnection(string connectionName)
        {
            ConnectionStringSettings setting = ConfigurationManager.ConnectionStrings[connectionName];

            if (setting == null)
            {
                throw new NullReferenceException("Connection string not found in configuration");
            }

            if (string.IsNullOrEmpty(setting.ProviderName))
            {
                throw new ProviderException("Provider name not specified in configuration");
            }

            return GetDatabaseType(setting);
        }
        #endregion

        #region Get database connection type
        /// <summary>
        /// Get the database type
        /// </summary>
        /// <param name="settings">Connection string settings</param>
        /// <returns>Connection based on configuration</returns>
        internal static IDbConnection GetDatabaseType(ConnectionStringSettings settings)
        {
            switch (settings.ProviderName)
            {
                case "System.Data.OleDb":
                    return new OleDbConnection(settings.ConnectionString);
                case "System.Data.SqlClient":
                    return new SqlConnection(settings.ConnectionString);
                case "System.Data.Odbc":
                    return new OdbcConnection(settings.ConnectionString);
                default:
                    {
                        try
                        {
                            Assembly assembly = Assembly.Load(settings.ProviderName);
                            string[] providerNamePart = settings.ProviderName.Split(".".ToCharArray()); 
                            IDbConnection connection = (IDbConnection)assembly.CreateInstance(settings.ProviderName + "." + providerNamePart[providerNamePart.Length - 1] + "Connection", true);
                            connection.ConnectionString = settings.ConnectionString;
                            return connection;
                        }
                        catch (Exception ex)
                        {
                            throw new ProviderException("Unable to create " + settings.ProviderName + " connection.\n" + ex.Message, ex);
                        }
                    }
            }
        }
        #endregion

        #region Create command
        /// <summary>
        /// Creates a command
        /// </summary>
        /// <param name="query">String query or Stored procedure</param>
        /// <param name="connectionName">Connect name from configuration</param>
        /// <param name="parameters">Command parameters</param>
        /// <param name="type">Command type</param>
        /// <returns>Configured command object with connection</returns>
        internal static IDbCommand CreateCommand(string query, string connectionName, Parameters parameters, System.Data.CommandType type)
        {
            IDbConnection connection = GetConnection(connectionName);
            IDbCommand command = CreateCommand(query, connection, parameters, type);
            return command;
        }

        /// <summary>
        /// Creates a command
        /// </summary>
        /// <param name="query">String query or Stored procedure</param>
        /// <param name="connection">Database connection</param>
        /// <param name="parameters">Command parameters</param>
        /// <param name="type">Command type</param>
        /// <returns>Configured command object with connection</returns>
        internal static IDbCommand CreateCommand(string query, IDbConnection connection, Parameters parameters, System.Data.CommandType type)
        {
            IDbCommand command = connection.CreateCommand();
            command.CommandType = type;
            command.CommandText = query;
            if (parameters != null && parameters.Count > 0)
            {
                parameters.GetParameters(ref command);
            }

            return command;
        }
        #endregion
    }
}
